home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 23 / AACD 23.iso / AACD / Utilities / BareED / DAC / source / Dump.c < prev    next >
C/C++ Source or Header  |  2001-06-22  |  33KB  |  993 lines

  1. /*
  2.     Copyright March 2001 J.v.d.Loo
  3.  
  4.     Treat  this  source  code and the load file based on this source as Freeware - I would say Public
  5.     Domain  when this wouldn't give other people the right to add their copyright signs - which among
  6.     other things can mean that the files Dump and Dump.c cannot be used freely...
  7.  
  8.     Start over:
  9.     This  file  is  not  meant as lesson how to use the "printer device" but as an example how to use
  10.     the (poor) DAC interface of BareED.
  11.  
  12.     Note:    Any DAC-application will be started from BareED!
  13.             A   DAC-application   will   get  a  normal  Workbench-start-up-message  with  additional
  14.             information and functions that it may use.
  15.             A  DAC-aaplication  may  be  written  as  base-relative  (small  code/data)  or  as large
  16.             code/data  model  - it doesn't matter. The base register A4 of your program is remembered
  17.             and restored by BareED!
  18.             ->  NOTE: Traditionally register A5 is used by the E-compiler - but currently BareED does
  19.                       not care about it - sorry.
  20.             If  a  CallBack-Hook  function of a DAC-application is called back you have to restore on
  21.             exit all registers to their initial state, except D0-D1, A0-A1, A4.
  22.  
  23.             Note well:    BareED  is  locked,  better  said:  protected  against modifications from the
  24.                         outside  (non-DAC-applications),  which means that the archive cannot be gone
  25.                         or  changed  when  there  is  still  at  least  one  DAC-application  alive -
  26.                         exception:  a  marked  block!!!  But the addresses of BlockStart and BlockEnd
  27.                         are still valid although the user could have already dismarked this block!
  28.  
  29.             Additional note:
  30.                         I  have  used  standard  Bitplanes and Bitmaps in this example although a 3rd
  31.                         party  graphic  board  software  could  be running and therewith non-standard
  32.                         Bitplanes  and Bitmaps (when used) would be more effective. But this requires
  33.                         on  OS  3.0  and 3.1 a patched "printer.device". As far as I know the OSs 3.5
  34.                         and 3.9 support non-standard Bitmaps native.
  35.  
  36.             Used printer by author:
  37.                         Since  I  found no "printer driver" for my Canon BJC 2000 printer, I've freed
  38.                         from  dust my old Epson LQ 400 printer and used it. Because the EpsonQ driver
  39.                         does  not compute page sizes correctly (2804 dots in horizontal and 0 dots in
  40.                         vertical  direction) I wrote a new "printer driver" called EpsonLQ that fixes
  41.                         these  and  other  bugs (now it supports also the Euro-sign). Since the Epson
  42.                         LQ  400 printer has only 180 dpi in vertical direction, the result of Dump is
  43.                         poor. Perhaps with a better printer (device ?) the result of Dump is better.
  44.  
  45.             Help needed:
  46.                         If  you  know  how  to apply "anti-alias" to a given font (or how to render a
  47.                         font  so  that  a  "anti-alias" text can be performed) give me a hint. If you
  48.                         already  managed to complete an useable routine please send it to me for free
  49.                         (email me in this case: Joergloo@aol.com).
  50.  
  51. Fixed bug in header (LocaleBase set up as STRUCT Library* instead of STRUCT LocalBase*).
  52. Fixed  crash  that  might  occur when Paused and right after Abandoned printout (now use of CMD_FLUSH
  53. instead of AbortIO() ).
  54. Modified layout of strings where now no Compiler can grumble about unknow escape sequences.
  55. Adapted this source to GNU-C - used this commandline:
  56.     > gcc -s -fbaserel -m68020 -O2 -fstrength-reduce -msmall-code -w -noixemul Dump.c
  57. */
  58.  
  59.  
  60. #include <exec/memory.h>
  61. #include <exec/libraries.h>
  62. #include <exec/ports.h>
  63.  
  64. #include <dos/dos.h>
  65.  
  66. #include <intuition/intuition.h>
  67. #include <intuition/screens.h>
  68. #include <intuition/preferences.h>
  69.  
  70. #include <graphics/gfxbase.h>
  71. #include <graphics/gfx.h>
  72. #include <graphics/displayinfo.h>
  73. #include <graphics/rastport.h>
  74. #include <graphics/text.h>
  75.  
  76. #include <libraries/locale.h>
  77.  
  78. #include <workbench/startup.h>
  79.  
  80. #include <devices/printer.h>
  81. #include <devices/prtbase.h>
  82.  
  83. #include <devices/printer.h>
  84. #include <devices/prtbase.h>
  85.  
  86. #include <clib/exec_protos.h>
  87. #include <clib/graphics_protos.h>
  88. #include <clib/intuition_protos.h>
  89. #include <clib/locale_protos.h>
  90. #include <clib/alib_protos.h>
  91. #include <clib/alib_stdio_protos.h>
  92.  
  93. #if !defined(__MAXON__) && !defined(__STORM__)
  94. #include <proto/exec.h>
  95. #include <proto/graphics.h>
  96. #include <proto/intuition.h>
  97. #include <proto/gadtools.h>
  98. #include <proto/locale.h>
  99. #else
  100. #include <pragma/exec_lib.h>
  101. #include <pragma/graphics_lib.h>
  102. #include <pragma/intuition_lib.h>
  103. #include <pragma/gadtools_lib.h>
  104. #include <pragma/locale_lib.h>
  105. #endif
  106.  
  107. #include <string.h>
  108.  
  109.  
  110. #if defined(__MAXON__) || defined(__STORM__)    /* ... enable Workbench start */
  111.  struct WBStartup *WBenchMsg = NULL;                    /* Variable */
  112.  #if defined(__MAXON__)
  113.   extern void wbparse( struct WBStartup *);
  114.  #endif
  115. void wbmain( struct WBStartup *ws)    /* This is called if we're running from WB */
  116. {
  117.     WBenchMsg = ws;     /* Remember message */
  118.     #if defined(__MAXON__)
  119.      wbparse( ws);        /* Parse WBench arguments (argv[0....])*/
  120.     #endif
  121. }
  122. #else
  123.  #if defined(__GNUC__)
  124.   extern struct WBStartup *_WBenchMsg;
  125.   #define WBenchMsg _WBenchMsg
  126.  #else
  127.   extern struct WBStartup *WBenchMsg;
  128.  #endif
  129. #endif
  130.  
  131. /* Macro by G. Nikl */
  132. #if defined(__GNUC__)
  133.  #define ASM
  134.  #define REG(reg,arg) arg __asm(#reg)
  135.  #else
  136.  #define REG(reg,arg) register __##reg arg
  137. #endif
  138.  
  139. #if defined(__MAXON__)
  140.  #define ASM
  141.  #define __saveds
  142. #endif
  143.  
  144. #if defined(__STORM__)
  145.  #define ASM
  146. #endif
  147.  
  148.  
  149. unsigned char VerStr[] = "$VER: DAC_Dump 21.13 (17-Apr-01)";
  150.  
  151.  
  152. struct ProgressBar            /* Don't use other items than this one of the ProgressBar... */
  153. {
  154.     struct Window *pb_Window;
  155. };    /* Don't rely on this end... */
  156.  
  157.  
  158. struct PseudoMsg
  159. {
  160.     struct WBStartup      pm_Startup;            /* Only readable! */
  161.     BPTR                 pm_Lock;                /* Hands off! */
  162.     unsigned char        *pm_Name;                /* Hands off! */
  163.     unsigned char         pm_FileName[108];        /* Hands off! */
  164.     unsigned char         pm_Dir[256];            /* Hands off! */
  165.     struct GfxBase        *pm_GfxBase;            /* At least v33 */
  166.     struct IntuitionBase *pm_IntuitionBase;        /* At least v36 */
  167.     struct Library        *pm_GadToolsBase;        /* At least v36 */
  168.     struct Library        *pm_DiskfontBase;        /* At least v33 */
  169.     struct Library        *pm_AslBase;            /* At least v38 */
  170.     struct Library        *pm_IconBase;            /* At least v33 */
  171.     struct LocaleBase    *pm_LocaleBase;            /* At least v1 */
  172.     struct Library        *pm_WorkbenchBase;        /* At least v36 */
  173.     void                *VisualInfo;            /* Never release it! */
  174.     struct DrawInfo        *DrawInfo;                /* Never release it! */
  175.     unsigned char        *pm_RegionStart;
  176.     unsigned int         pm_RegionSize;
  177.     unsigned char        *pm_TextStart;
  178.     unsigned char        *pm_TextEnd;
  179.     unsigned char        *pm_BlockStart;
  180.     unsigned char        *pm_BlockEnd;
  181.     struct TextAttr        *pm_FontAttr;
  182.     struct TextFont        *pm_Font;
  183.     struct Window        *pm_EdWindow;
  184.     unsigned int         pm_TabWidth;            /* In pixels */
  185.     unsigned int         pm_TabStops;            /* A tap stop occurs every 'n' */
  186.     unsigned int         pm_RightMargin;
  187.     unsigned char        *pm_CharSpace;            /* Pointer to the character-spaces of the used font */
  188.     void                (*pm_GetAttr)( struct TagItem *taglist);        /* Currently NULL (out of order!) */
  189.     void                (*pm_ChangeAttr)( struct TagItem *taglist);        /* Currently NULL (out of order!) */
  190.     void                (*pm_BlockInput)( void);
  191.     void                (*pm_AllowInput)( void);
  192.     void                (*pm_Tell)( STRPTR str);
  193.     unsigned int        (*pm_CaseTell)( STRPTR str);
  194.     unsigned int        (*pm_RequestNumber)( unsigned int initial, STRPTR winname, STRPTR hailtext,\
  195.                                              STRPTR gadtext, BOOL zero);
  196.     unsigned int        (*pm_StrPixelLen)( unsigned char *start, unsigned char *end);
  197.     void                (*pm_DumpStrLine)( unsigned char *start, unsigned char *end, struct RastPort *rp,\
  198.                                            unsigned int x, unsigned int y);
  199.     unsigned int        (*pm_WidestStrLen)( unsigned char *text, unsigned char *stop,\
  200.                                             unsigned int (*inform_code)( unsigned int len, unsigned int line),\
  201.                                             unsigned int inform);
  202.     void                (*pm_DumpStrings)( struct RastPort *rp,\
  203.                                            unsigned int (*dump_code)( unsigned int len, unsigned int line),\
  204.                                            unsigned char *text, unsigned char *stop);
  205.     void                (*pm_FreeProgressBar)( struct ProgressBar *pb);
  206.     struct ProgressBar *(*pm_CreateProgressBar)( STRPTR wintitle, STRPTR hail, STRPTR stop, STRPTR cont, STRPTR cancel);
  207.     unsigned int        (*pm_PullPBarEvent)( struct ProgressBar *pb);
  208.     void                (*pm_ChangePBarIndicator)( struct ProgressBar *pb, unsigned int percent, STRPTR hail);
  209. /* Following does not yet work properly - so don't use! */
  210.     void                (*pm_TogglePBarGad)( struct ProgressBar *pb);
  211. };
  212.  
  213.  
  214. /* ----------------------------------------------------------------------------------------------- */
  215.  
  216. struct PseudoMsg *PsMsg;    /* Message got from BareED */
  217.  
  218. struct IntuitionBase *IntuitionBase;
  219. struct GfxBase *GfxBase;
  220. struct LocaleBase *LocaleBase;
  221. struct Library *GadToolsBase;
  222.  
  223. struct Catalog *Cat;
  224.  
  225. union PrinterIO
  226. {
  227.     struct IOStdReq    IoStd;
  228.     struct IODRPReq    IoDpRP;
  229.     struct IOPrtCmdReq IoPrtCom;
  230. };
  231.  
  232. struct MsgPort    *PrinterPort;
  233. union  PrinterIO *PIO;
  234. struct PrinterData *PD;
  235. struct PrinterExtendedData *PED;
  236.  
  237. struct ProgressBar *PB;        /* Will be created */
  238.  
  239. struct RastPort *FakeRP;
  240. struct BitMap *FakeBM;
  241. struct ColorMap *CM;
  242.  
  243. /* Since "printer device" destroys them, I have to remember them! */
  244. unsigned int DestHDots, DestVDots, ModeID;
  245. unsigned int VDotsPage, VDotsLine, HDotsLine, Lines;
  246.  
  247. /* Want to show user how much alredy worked out... */
  248. unsigned int Lines2Dump;    /* Amount total lines in printout */
  249.  
  250. #define TEXTBUFFERSIZE 256    /* Storage size (buffer) for strings */
  251. STRPTR TextBuffer;
  252.  
  253. BOOL Continue = TRUE;        /* While Continue is TRUE we continue - when FALSE, we quit */
  254.  
  255. BOOL IoStarted = FALSE;        /* When the IO is in progress, it will be TRUE */
  256.  
  257. /* Offset on paper and keep track of actual line dumped */
  258. unsigned CurrYdot, CurrLine;
  259.  
  260.  
  261. /* Possible printer.device and I/O errors */
  262. STRPTR ErrorText[] =
  263. {
  264.     "\000\x0A No error",
  265.     "\000\x0B Printing-progress aborted",
  266.     "\000\x0C Not a graphic printer",
  267.     "\000\x0D HAM image cannot be converted",        /* Cannot occur */
  268.     "\000\x0E Too large region to dump",
  269.     "\000\x0F Out of supported dimension",            /* Cannot occur */
  270.     "\000\x10 Not enough memory",
  271.     "\000\x11 Not enough memory for print-buffer",
  272.     "\000\x12 IO: Open device failed",
  273.     "\000\x13 IO: Printing-progress aborted",
  274.     "\000\x14 IO: Unsupported command",
  275.     "\000\x15 IO: Command length did not match"
  276. };
  277.  
  278. /* ---------------------------------------------------------------------
  279.     I don't want to waste memory so I use an own made SPrintf() function
  280.     which is much shorter (it doesn't support floats and word descriptions)
  281.     than the original!
  282. */
  283.  
  284. #if defined(__MAXON__)
  285. void ASM funny_code( REG(a3, char *buf), REG(d0, char c))
  286. {
  287.     *buf++ = c;    // move.b d0,(a3)+
  288. }                // rts
  289. #else
  290. unsigned short funny_code[] =
  291. {
  292.     0x16c0,
  293.     0x4e75
  294. };
  295. #endif
  296.  
  297. #define FUNC (void (*)()) &funny_code    /* Code should use: lea funny_code(An),a2 */
  298.  
  299. void SPrintf( char *buf, char *descr, ...)
  300. {
  301.     char *args;
  302.  
  303.     (char *) args = (char *) &descr;    /* Address format string on stack */
  304.     args += 4;                            /* Address 1st additional argument */
  305.     RawDoFmt( descr, args, FUNC, buf);
  306. }
  307.  
  308. /* -----------------------
  309.     Multilingual stuff...
  310.  
  311.     NOTE: I prepared the strings so that they contain a leading word, which is set up as follow:
  312.           1st byte (an octal number)
  313.           2nd byte (an octal or hexadecimal number)
  314.           3rd byte - dummy (space character)
  315.           4th byte - string start
  316.           The  first two bytes (= one word) will be converted by GStr() to a longword - used as index
  317.           in the catalogue.
  318. */
  319.  
  320. void OpenTheCatalog()
  321. {
  322.     Cat = (struct Catalog *) OpenCatalogA( 0, "dac_dump.catalog", 0);
  323. }
  324.  
  325. void CloseTheCatalog()
  326. {
  327.     if (Cat)
  328.         CloseCatalog( Cat);
  329. }
  330.  
  331. char * GStr( char *str)
  332. {
  333.     ULONG no;
  334.     char *rstr;
  335.  
  336.     no     = 0;
  337.     no     = ( (UBYTE) str[0] << 8) + (UBYTE) str[1];    /* Convert the two leading bytes of string into longword */
  338.     rstr = &str[3];                                    /* String's start */
  339.  
  340.     if (Cat)
  341.         rstr = (char *) GetCatalogStr( Cat, no, rstr);    /* Get string or the default... */
  342.  
  343.     return rstr;
  344. }
  345.  
  346.  
  347. /* ---------------------------------
  348.     CallBack Hook for WidestStrLen()
  349.  
  350.     No need here to save / load base register! - already done!
  351.  
  352.     Inform user if a line exeeds the computed limit. Routine
  353.     called from the inside of WidestStrLen() !
  354. */
  355.  
  356. unsigned int InformCode( unsigned int len, unsigned int line)
  357. {
  358.     unsigned int limit;
  359.  
  360.     limit = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  361.  
  362.     SPrintf( TextBuffer, GStr( "\001\001 Line %ld exceeds with %ld pixels limit of %ld pixels!\n\n"\
  363.                                "Continue anyhow?"), line, len, limit);
  364.     Continue = PsMsg->pm_CaseTell( TextBuffer);
  365.  
  366.     return Continue;
  367. }
  368.  
  369.  
  370. /* --------------------------------
  371.     CallBack Hook for DumpStrings()
  372.  
  373.     No need here to save / load base register! - already done!
  374.  
  375.     This routine is called from DumpStrings() - when DumpStrings()
  376.     has laid out a new line - thus we can here dump the Raster Port
  377.     contents to the printer. Meanwhile we check for user actions -
  378.     like pause, continue or abandon the printout. 
  379. */
  380.  
  381. unsigned int DumpCode( unsigned int len, unsigned int line)
  382. {
  383.     BOOL cont = TRUE;
  384.     unsigned int signal, sigPrt, sigWd, id, spec, flag, percent, permil, loop;
  385.     int i;
  386.  
  387.     /* Check if the dump will need a new page */
  388.     if ( VDotsPage < CurrYdot + VDotsLine)    /* Fits this line onto paper? */
  389.     {
  390.         /* Remember both - to set them later on! */
  391.         spec = PIO->IoDpRP.io_Special;
  392.         flag = PIO->IoDpRP.io_Flags;
  393.  
  394.         PIO->IoStd.io_Flags = IOF_QUICK;    /* Need no reply from "printer.device" */
  395.         PIO->IoStd.io_Command = CMD_WRITE;
  396.         PIO->IoStd.io_Length = 1;
  397.         PIO->IoStd.io_Data = "\014";        /* Eject page (12 = FormFeed) */
  398.  
  399.         if (IoStarted)
  400.             WaitIO(  (struct IORequest *) PIO);    /* Wait until line has been dumped */
  401.         IoStarted = FALSE;
  402.         if ( DoIO( (struct IORequest *) PIO))
  403.             cont = PsMsg->pm_CaseTell( GStr( "\000\x16 Error occurred while ejecting the page!\n\n"\
  404.                                              "Continue anyway?") );
  405.         IoStarted = cont;
  406.         /* Re-do for graphic dump */
  407.         PIO->IoDpRP.io_Command = PRD_DUMPRPORT;
  408.         PIO->IoDpRP.io_Flags = flag;
  409.         PIO->IoDpRP.io_RastPort = FakeRP;
  410.         PIO->IoDpRP.io_ColorMap = CM;
  411.         PIO->IoDpRP.io_Modes = ModeID;
  412.         PIO->IoDpRP.io_SrcX = 0;
  413.         PIO->IoDpRP.io_SrcY = 0;
  414.         PIO->IoDpRP.io_SrcWidth = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  415.         PIO->IoDpRP.io_SrcHeight = PsMsg->pm_Font->tf_YSize + 1;
  416.         PIO->IoDpRP.io_Special = spec;
  417.         PIO->IoDpRP.io_DestCols = DestHDots;
  418.         PIO->IoDpRP.io_DestRows = DestVDots;
  419.  
  420.         CurrYdot = 0;    /* Set to top of page */
  421.     }
  422.  
  423.     if (cont == TRUE)
  424.     {
  425.         /* Send to printer... */
  426.         if (IoStarted)
  427.             WaitIO( (struct IORequest *) PIO);    /* Wait for last action to be completed */
  428.         SendIO( (struct IORequest *) PIO);        /* Attempt to dump Raster Port */
  429.         IoStarted = TRUE;
  430.         CurrYdot += VDotsLine;                    /* Next offset (plus full line) */
  431.         CurrLine ++;                            /* One more line dumped */
  432.  
  433.         /* In case the progress-bar is accessible... */
  434.         if (PB)
  435.         {
  436.             percent = CurrLine * 100 / Lines2Dump;    /* How much in percent already worked out? */
  437.             permil  = CurrLine * 1000 / Lines2Dump;
  438.             permil  = permil - (percent * 10); 
  439.             SPrintf( TextBuffer, GStr( "\000\x46 Printout completed to %ld.%ld %%"), percent, permil);
  440.             PsMsg->pm_ChangePBarIndicator( PB, percent, TextBuffer);
  441.         }
  442.  
  443.         /* The following construct emulates the WaitIO() function but gives us
  444.            also the chance to set and wait for other, non "printer device" related
  445.            things, here break signal (CTRL-C) and progress-bar message
  446.         */
  447.         sigPrt = 1 << PrinterPort->mp_SigBit;                    /* Signal-bitmask of printer */
  448.         if (PB)
  449.             sigWd  = 1 << PB->pb_Window->UserPort->mp_SigBit;    /* and ditto for progress-bar */
  450.                 else
  451.             sigWd = 0;
  452.         signal = Wait( SIGBREAKF_CTRL_C | sigPrt | sigWd );        /* Cheap sleep! */
  453.  
  454.  
  455.         /* Break signal from the outside (system monitor) ? */
  456.         if ( (signal & SIGBREAKF_CTRL_C) )
  457.         {
  458.             AbortIO( (struct IORequest *) PIO);
  459.             if (IoStarted)
  460.                 WaitIO( (struct IORequest *) PIO);    /* Convention */
  461.             PsMsg->pm_Tell( GStr ("\000\x17 Printing abandoned by user!") );
  462.             cont = FALSE;
  463.         }
  464.  
  465.  
  466.         /* Message from "printer device" ? */
  467.         if (cont == TRUE)
  468.         {
  469.             if ( (signal & sigPrt) )
  470.                 while ( GetMsg( PrinterPort));    /* Remove only the message */
  471.  
  472.             /* Check for error */
  473.             if (PIO->IoDpRP.io_Error)
  474.             {
  475.                 i = PIO->IoDpRP.io_Error;
  476.                 if (i < 0)                    /* IO error ? */
  477.                     i = i * -1 + 7;            /* Map to offset in table */
  478.                 SPrintf( TextBuffer, GStr( "\000\x18 Error: %s"), GStr( ErrorText[i]) );
  479.                 PsMsg->pm_Tell( TextBuffer);                                    
  480.                 cont = FALSE;
  481.             }
  482.         }
  483.  
  484.  
  485.         /* Progress-bar message? */
  486.         if (cont == TRUE)
  487.         {
  488.             if ( (signal & sigWd) )
  489.             {
  490.                 id = PsMsg->pm_PullPBarEvent( PB);    /* Get id of gadget clicked */
  491.  
  492.                 /* Pause? */
  493.                 if (id == 2)
  494.                 {
  495.                     spec = PIO->IoDpRP.io_Special;        /* Remember current state */
  496.                     flag = PIO->IoDpRP.io_Flags;
  497.  
  498.                     WaitIO( (struct IORequest *) PIO);    /* Wait for dump in progress to be completed */
  499.                     PIO->IoStd.io_Flags = IOF_QUICK;    /* Need no reply */
  500.                     PIO->IoStd.io_Command = CMD_STOP;    /* Stop dump (already completed but necessary) */
  501.                     DoIO( (struct IORequest *) PIO);    /* Do it now! */
  502.                     IoStarted = FALSE;
  503.  
  504.                     loop = TRUE;
  505.                     while (loop)
  506.                     {
  507.                         signal = Wait( SIGBREAKF_CTRL_C | sigPrt | sigWd);
  508.                     
  509.                         /* A break signal from the outside? */
  510.                         if (signal & SIGBREAKF_CTRL_C)
  511.                         {
  512.                             AbortIO( (struct IORequest *) PIO);
  513.                             if (IoStarted)
  514.                                 WaitIO( (struct IORequest *) PIO);    /* Convention */
  515.                             PsMsg->pm_Tell( GStr ("\000\x17 Printing abandoned by user!") );
  516.                             cont = FALSE;
  517.                             loop = FALSE;
  518.                         }
  519.  
  520.  
  521.                         if (cont && loop)
  522.                         {
  523.                             /* Message from device? - can only be "stopped"! */
  524.                             if ( (signal & sigPrt) )
  525.                                 while ( GetMsg( PrinterPort));    /* Remove only the message */
  526.  
  527.                             /* Check for error */
  528.                             if (PIO->IoDpRP.io_Error)
  529.                             {
  530.                                 i = PIO->IoDpRP.io_Error;
  531.                                 if (i < 0)                    /* IO error ? */
  532.                                     i = i * -1 + 7;            /* Map to offset in table */
  533.                                 SPrintf( TextBuffer, GStr( "\000\x18 Error: %s"), GStr( ErrorText[i]) );
  534.                                 PsMsg->pm_Tell( TextBuffer);                                    
  535.                                 cont = FALSE;
  536.                                 loop = FALSE;
  537.                             }
  538.                         }
  539.  
  540.  
  541.                         /* Message from progress-bar? - note: we're paused! */
  542.                         if ( loop && (signal & sigWd) )
  543.                         {
  544.                             id = PsMsg->pm_PullPBarEvent( PB);    /* Get id of gadget clicked */
  545.  
  546.                             if (id == 2)    /* awake? */
  547.                             {
  548.                                 PIO->IoStd.io_Flags = IOF_QUICK;
  549.                                 PIO->IoStd.io_Command = CMD_START;    /* Continue dump (i.e. tell device we're */
  550.                                 DoIO( (struct IORequest *) PIO);    /* going to re-use it) */
  551.  
  552.                                 /* Re-do for graphic dump */
  553.                                 PIO->IoDpRP.io_Command = PRD_DUMPRPORT;
  554.                                 PIO->IoDpRP.io_Flags = flag;
  555.                                 PIO->IoDpRP.io_RastPort = FakeRP;
  556.                                 PIO->IoDpRP.io_ColorMap = CM;
  557.                                 PIO->IoDpRP.io_Modes = ModeID;
  558.                                 PIO->IoDpRP.io_SrcX = 0;
  559.                                 PIO->IoDpRP.io_SrcY = 0;
  560.                                 PIO->IoDpRP.io_SrcWidth = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  561.                                 PIO->IoDpRP.io_SrcHeight = PsMsg->pm_Font->tf_YSize + 1;
  562.                                 PIO->IoDpRP.io_Special = spec;
  563.                                 PIO->IoDpRP.io_DestCols = DestHDots;
  564.                                 PIO->IoDpRP.io_DestRows = DestVDots;
  565.                                 loop = FALSE;
  566.                             }
  567.                             else
  568.                             {
  569.                                 if (id == 1)    /* Shame on user, firstly paused now abandoned... */
  570.                                 {
  571.  
  572.                                     PIO->IoStd.io_Flags = IOF_QUICK;
  573.                                     PIO->IoStd.io_Command = CMD_FLUSH;    /* Abort halted IO-requests */
  574.                                     DoIO( (struct IORequest *) PIO);
  575.                                     if (IoStarted)
  576.                                         WaitIO( (struct IORequest *) PIO);
  577.                                     PsMsg->pm_Tell( GStr ("\000\x17 Printing abandoned by user!") );
  578.                                     cont = FALSE;
  579.                                     loop = FALSE;
  580.                                 }
  581.                             }
  582.                         }
  583.                     }
  584.                 }
  585.                 else
  586.                 {
  587.                     /* User said stop and quit? */
  588.                     if (id == 1)
  589.                     {
  590.                         AbortIO( (struct IORequest *) PIO);
  591.                         if (IoStarted)
  592.                             WaitIO( (struct IORequest *) PIO);
  593.                         PsMsg->pm_Tell( GStr ("\000\x17 Printing abandoned by user!") );
  594.                         cont = FALSE;
  595.                     }
  596.                 }
  597.             }
  598.         }    /* End progress-bar message */
  599.  
  600.  
  601.         /* Firstly, clear the complete bit-plane(s) */
  602.         SetDrMd( FakeRP, JAM2);        /* We want to overwrite */
  603.         SetAPen( FakeRP, 0);        /* Background pen */
  604.         RectFill( FakeRP, 0, 0, FakeBM->BytesPerRow * 8 - 1, FakeBM->Rows - 1);
  605.  
  606.         /* Set render pen - to make the characters visible */
  607.         SetAPen( FakeRP, 1);        /* Foreground pen */
  608.     }
  609.  
  610.     return cont;
  611. }
  612.  
  613. /* ----------------------------------------------------
  614.     Try to dump the specified characters to the printer
  615.  
  616.     Called with the widest string length in pixels.
  617.  
  618.     NOTE:
  619.         The 'FakeBM->Depth' must have already been set to the required depth -
  620.         in this example it was set to one (monochrome).
  621. */
  622.  
  623. void DoTheDump( unsigned int mustHave)
  624. {
  625.     unsigned int i, a, r, p;
  626.     unsigned char *curr, *end;
  627.  
  628.     a = mustHave / PsMsg->pm_CharSpace[ (UBYTE) ' '];
  629.  
  630.     if (PsMsg->pm_RightMargin < a)
  631.         i = PsMsg->pm_CaseTell( GStr( "\001\002 Sure to continue with printout\n"\
  632.                                       "although not all characters fit onto concerned page?\n"\
  633.                                       "(Some beyond right margin - non-printable!)\n\n"\
  634.                                       "Continue?") );
  635.     if (i)
  636.     {
  637.         /* Compute size in bytes for bit-plane allocation */
  638.         i = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];    /* Size in pixels */
  639.         i = (i + 15) & -16;            /* 16-bit boundary */
  640.         i /= 8;                        /* ...in bytes */
  641.         FakeBM->BytesPerRow = i;    /* Amount of rows */
  642.  
  643.         FakeBM->Rows = PsMsg->pm_Font->tf_YSize + 1;
  644.  
  645.         if (GfxBase->LibNode.lib_Version <= 38 \
  646.             || (GetBitMapAttr( PsMsg->pm_EdWindow->WScreen->RastPort.BitMap, BMA_FLAGS) & BMF_STANDARD))
  647.         {
  648.             /* Standard (PLANAR) display - so the bitplanes must reside in CHIP-RAM -
  649.                for the rendering functions
  650.             */
  651.             FakeBM->Planes[0] = (PLANEPTR) AllocMem( FakeBM->BytesPerRow * FakeBM->Rows * FakeBM->Depth, \
  652.                                                      MEMF_CLEAR|MEMF_CHIP);
  653.         }
  654.         else
  655.         {
  656.             /* There is a non-standard Bitmap - so I guess rendering to FAST-RAM will work! */
  657.             FakeBM->Planes[0] = (PLANEPTR) AllocMem( FakeBM->BytesPerRow * FakeBM->Rows * FakeBM->Depth, MEMF_CLEAR);
  658.         }
  659.  
  660.         /* Bitplane(s) allocated? */
  661.         if ( FakeBM->Planes[0])
  662.         {
  663.             /* If the Bitmap has got more than 1 Bitplane the construct below will
  664.                compute the other Bitplane addresses and stores them into the Bitmap
  665.             */
  666.             a = (unsigned int) FakeBM->Planes[0];    /* Address allocated memory, bitplane[0] already set! */
  667.             for (i = 1; i < FakeBM->Depth; i++)        /* Do it for the others (?) */
  668.             {
  669.                 a += FakeBM->BytesPerRow * FakeBM->Rows;    /* Plus size of one, single bitplane */
  670.                 FakeBM->Planes[i] = (PLANEPTR) a;            /* Store computed address */
  671.             }
  672.  
  673.             /* Figure out if user wishes only to dump the marked area */
  674.             if (PsMsg->pm_BlockStart)
  675.             {
  676.                 curr = PsMsg->pm_BlockStart;
  677.                 end = PsMsg->pm_BlockEnd;
  678.             }
  679.             else    /* No marked area, so take whole archive */
  680.             {
  681.                 curr = PsMsg->pm_TextStart;
  682.                 end = PsMsg->pm_TextEnd;
  683.             }
  684.  
  685.             /* How many lines are in the archive/text block ? */
  686.             a = 1;
  687.             while (curr < end && *curr != 0)
  688.                 if (*curr++ == 10)    /* Count linefeeds */
  689.                     a++;
  690.             Lines2Dump = a;        /* Remember for later */
  691.  
  692.             /* How many lines can be displayed per printer page? */
  693.             i = PD->pd_Preferences.PaperLength;        /* Lines per page */
  694.  
  695.             /* How many lines can be displayed per inch */
  696.             if (PD->pd_Preferences.PrintSpacing)
  697.                 r = 8;
  698.                     else
  699.                 r = 6;
  700.  
  701.             /* How many dots can be printed out to one page in vertical direction? */
  702.             i = i * PED->ped_YDotsInch / r;        /* e.g. 66 lines * 180 dpi / 6 lines per page */
  703.  
  704.             /* How many pages required to print out those lines? */
  705.             p = a * PIO->IoDpRP.io_DestRows / i;
  706.             if (!p)
  707.                 p = 1;    /* At least one page! */
  708.  
  709.             /* Check if there is a rest of lines that need an extra page,
  710.                e.g. 60 lines per page , 153 lines to print but only 2 pages computed!
  711.             */
  712.             if (a > p * i / PIO->IoDpRP.io_DestRows)
  713.                 p ++;
  714.  
  715.             /* Give the user the chance to abort printing... */
  716.             SPrintf( TextBuffer, GStr( "\001\003 Sure to print?\n\nPrintout would require %ld pages!"), p);
  717.             p = PsMsg->pm_CaseTell( TextBuffer);
  718.             if (p)
  719.             {
  720.                 /*
  721.                     'i' contains vertical dots per page, e.g. 1920,
  722.                     'a' contains amount lines to print
  723.                     'PIO->IoDpRP.io_DestCols' contains horizontal dots for a single line to print
  724.                     'PIO->IoDpRP.io_DestRows' contains vertical dots for a single line to print
  725.                 */
  726.                 VDotsPage = i;
  727.                 VDotsLine = PIO->IoDpRP.io_DestRows;
  728.                 HDotsLine = PIO->IoDpRP.io_DestCols;
  729.                 Lines     = a;
  730.                 CurrYdot = 0;    /* Imagine we're at the top of a page */
  731.                 CurrLine = 0;    /* No lines printed (yet) */
  732.  
  733.                 CM = GetColorMap( 2);    /* Monochrome - only two colours */
  734.                 if (CM)
  735.                 {
  736.                     SetRGB4CM( CM, 0, 0xF, 0xF, 0xF);    /* Background = white */
  737.                     SetRGB4CM( CM, 1, 0x0, 0x0, 0x0);    /* Foreground = black */
  738.  
  739.                     /* Establish this colour-map for dump */
  740.                     PIO->IoDpRP.io_ColorMap = CM;
  741.  
  742.                     /* We really want to print! */
  743.                     PIO->IoDpRP.io_Special &= ~SPECIAL_NOPRINT;
  744.  
  745.                     SetDrMd( FakeRP, JAM2);        /* We want to overwrite */
  746.                     SetAPen( FakeRP, 1);        /* Foreground pen */
  747.                     SetBPen( FakeRP, 0);        /* Background pen */
  748.  
  749.                     PB = PsMsg->pm_CreateProgressBar( GStr( "\002\001 DAC Dumper"), \
  750.                                                       GStr( "\000\x42 Printout completed to 0.0"), \
  751.                                                       GStr( "\000\x43 Pause/Continue"), GStr( "\000\x44 Continue"), \
  752.                                                       GStr( "\000\x45 Abandon") );
  753.  
  754.                     /* Continue even the progress-bar has not been attached to Dump */
  755.                     if (PsMsg->pm_BlockStart)
  756.                         PsMsg->pm_DumpStrings( FakeRP, &DumpCode, PsMsg->pm_BlockStart, PsMsg->pm_BlockEnd);
  757.                             else
  758.                         PsMsg->pm_DumpStrings( FakeRP, &DumpCode, PsMsg->pm_TextStart, PsMsg->pm_TextEnd);
  759.  
  760.                     if (PB)
  761.                         PsMsg->pm_FreeProgressBar( PB);
  762.  
  763. /*    REMOVED - since it should be clear...
  764.                     PsMsg->pm_Tell( GStr( "\002\004 Print-job done.") ); */
  765.  
  766.                     FreeColorMap( CM);
  767.                 }
  768.                 else
  769.                     PsMsg->pm_Tell( GStr( "\000\x19 Cannot create unicoloured colour-map!") );
  770.             }
  771.             FreeMem( FakeBM->Planes[0], FakeBM->BytesPerRow * FakeBM->Rows * FakeBM->Depth);
  772.         }
  773.         else
  774.             PsMsg->pm_Tell( GStr( "\000\x1A Unable to get RAM for printout!") );
  775.     }
  776.     else
  777.         PsMsg->pm_Tell( GStr( "\000\x1B Print-job aborted...") );
  778.  
  779. }
  780.  
  781.  
  782. /* ###############################################################
  783.     Here we go...
  784. */
  785.  
  786. int main( int argc, char **argv)
  787. {
  788.     struct ViewPort *vp;
  789.     int a, i, p, l;
  790.  
  791.     /* Discover if we have been launched by Workbench */
  792.     if ( !WBenchMsg)
  793.         return 0;
  794.  
  795.     /* Either from Workbench or BareED */
  796.     if ( strcmp( WBenchMsg->sm_Message.mn_Node.ln_Name, "BAREED") != NULL)
  797.          return 0;
  798.  
  799.     /* Was BareED, so convert pointer to the message */
  800.     PsMsg = (struct PseudoMsg *) WBenchMsg;
  801.  
  802.     GfxBase = PsMsg->pm_GfxBase;
  803.     IntuitionBase = (struct IntuitionBase *) PsMsg->pm_IntuitionBase;
  804.     LocaleBase = PsMsg->pm_LocaleBase;
  805.     GadToolsBase = PsMsg->pm_GadToolsBase;
  806.  
  807.     OpenTheCatalog();
  808.  
  809.     TextBuffer = (STRPTR) AllocMem( TEXTBUFFERSIZE, MEMF_CLEAR);
  810.     FakeRP = (struct RastPort *) AllocMem( sizeof( struct RastPort), MEMF_CLEAR);
  811.     FakeBM = (struct BitMap *) AllocMem( sizeof( struct BitMap), MEMF_CLEAR);
  812.  
  813.     if (TextBuffer && FakeRP && FakeBM)
  814.     {
  815.         /* Create non-public message port */
  816.         if ( (PrinterPort = CreateMsgPort()) )
  817.         {
  818.             /* Allocate PrinterIO - for easier access as union */
  819.             if ( (PIO = (union PrinterIO *) CreateExtIO( PrinterPort, sizeof( union PrinterIO))) )
  820.             {
  821.                 /* Open the printer.device */
  822.                 if ( !(OpenDevice( "printer.device", 0, (struct IORequest *) PIO, 0)) )
  823.                 {
  824.                     PD = (struct PrinterData *) PIO->IoDpRP.io_Device;
  825.                     PED = (struct PrinterExtendedData *) &PD->pd_SegmentData->ps_PED;
  826.  
  827.                     vp = &(PsMsg->pm_EdWindow->WScreen->ViewPort);
  828.  
  829.                     /* Get the mode-id to compute correct aspect ratio */
  830.                     if ( (ModeID = GetVPModeID( vp)) != INVALID_ID)
  831.                     {
  832.                         /*    Create a faked Raster Port so that a BAD DIMENSION error is nearly impossible!
  833.                             To do this:
  834.                                 Tell the "printer.device" that the faked Bitmap is in horizontal direction
  835.                                 ten times larger than screen's! Could also be done with a fixed-width size,
  836.                                 e. g. 16000.
  837.                             Since no rendering is performed, we can play with empty bitplanes!
  838.                         */
  839.  
  840.                         /* Duplicate Raster Port - a bad hack? */
  841.                         CopyMem( PsMsg->pm_EdWindow->RPort, FakeRP, sizeof( struct RastPort));
  842.                         FakeRP->Layer = 0;
  843.                         FakeRP->BitMap = FakeBM;
  844.                         FakeBM->BytesPerRow = PsMsg->pm_EdWindow->WScreen->Width * 10 / 8;
  845.                         FakeBM->Rows = PsMsg->pm_EdWindow->WScreen->Height;
  846.                         FakeBM->Depth = 1;
  847.  
  848.                         /* Fill in parts of the IODRPRequest - used to compute correct aspect ratio */
  849.                         PIO->IoDpRP.io_Command = PRD_DUMPRPORT;
  850.                         PIO->IoDpRP.io_RastPort = FakeRP;
  851.                         PIO->IoDpRP.io_ColorMap = vp->ColorMap;
  852.                         PIO->IoDpRP.io_Modes = ModeID;
  853.                         PIO->IoDpRP.io_SrcX = 0;
  854.                         PIO->IoDpRP.io_SrcY = 0;
  855.  
  856.                         /* We need a valid right margin to compute and lay out strings! */
  857.                         while (PsMsg->pm_RightMargin == NULL)
  858.                             PsMsg->pm_RightMargin = PsMsg->pm_RequestNumber( 0, GStr( "\002\001 DAC Dumper"),\
  859.                                                                                 GStr( "\002\002 Enter right margin!"),\
  860.                                                                                 GStr( "\002\003 Okay"), 0);
  861.  
  862.                         /* How long is a line in pixels? */
  863.                         PIO->IoDpRP.io_SrcWidth = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  864.  
  865.                         /* How high is the font (plus one because BareED reserves between each text line a row! */ 
  866.                         PIO->IoDpRP.io_SrcHeight = PsMsg->pm_Font->tf_YSize + 1;
  867.  
  868.                         /* We don't want to print, but we want to know the correct dimension */
  869.                         PIO->IoDpRP.io_Special = SPECIAL_ASPECT|SPECIAL_NOFORMFEED|SPECIAL_TRUSTME|SPECIAL_NOPRINT;
  870.  
  871.                         /* Initialise with zero so "printer device" calculates dump dimension! */
  872.                         PIO->IoDpRP.io_DestCols = 0;
  873.                         PIO->IoDpRP.io_DestRows = 0;
  874.  
  875.                         /* Ask for dimension */
  876.                         DoIO( (struct IORequest *) PIO);
  877.  
  878.                         if (PIO->IoDpRP.io_Error == 0)
  879.                         {
  880.                             DestHDots = p = PIO->IoDpRP.io_DestCols;    /* Dots in horizontal direction
  881.                                                                            (to fit line fulfilled onto paper) */
  882.                             DestVDots = l = PIO->IoDpRP.io_DestRows;    /* Dots in vertical direction (height of
  883.                                                                             one single line!) */
  884.                         }
  885.                         else
  886.                         {
  887.                             a = PIO->IoDpRP.io_Error;
  888.                             if (a < 0)
  889.                                 a = a * -1 + 7;
  890.  
  891.                             SPrintf( TextBuffer, GStr( "\000\x18 Error: %s"), GStr( ErrorText[a]));
  892.                             PsMsg->pm_Tell( TextBuffer);                                    
  893.                         }
  894.  
  895.                         /* Do not continue upon error */
  896.                         if ( !PIO->IoDpRP.io_Error)
  897.                         {
  898.                             /* How wide is a string basing on RightMargin (in pixels -
  899.                                as limit for WidestStrLen()) ?
  900.                             */
  901.                             a = PsMsg->pm_RightMargin * PsMsg->pm_CharSpace[ (UBYTE) 32];
  902.  
  903.                             /* Get the height of the font and care about the row that BareED reserves
  904.                                between each text line
  905.                             */
  906.                             i = PsMsg->pm_Font->tf_YSize + 1;
  907.  
  908.                             SPrintf( TextBuffer, GStr( "\000\x40 Dimension when using a right margin of %ld" \
  909.                                                        " characters:\n\nline length = %4ld pixles = X-dots = %4ld\n" \
  910.                                                        "line height = %4ld pixels = Y-dots = %4ld"), \
  911.                                                         PsMsg->pm_RightMargin, a, p, i, l);
  912.                             PsMsg->pm_Tell( TextBuffer);
  913.  
  914.                             /* Invoke function WidestStrLen() with a set CallBack-Hook */ 
  915.                             if (PsMsg->pm_BlockStart)
  916.                                 p = PsMsg->pm_WidestStrLen( PsMsg->pm_BlockStart, PsMsg->pm_BlockEnd,\
  917.                                                             &InformCode, a);
  918.                                     else
  919.                                 p = PsMsg->pm_WidestStrLen( PsMsg->pm_TextStart, PsMsg->pm_TextEnd,\
  920.                                                             &InformCode, a);
  921.  
  922.                             /* Did the user abandoned computing? */
  923.                             if (Continue)
  924.                             {
  925.                                 /* No... */
  926.                                 l = p / PsMsg->pm_CharSpace[ (UBYTE) 32];
  927.                                 if ( l * PsMsg->pm_CharSpace[ (UBYTE) 32] < p)    /* Correct number of chars! */
  928.                                     l ++;
  929.  
  930.                                 SPrintf( TextBuffer, GStr( "\000\x41 Widest line: %ld pixels or %ld characters!"), p, l);
  931.                                 PsMsg->pm_Tell( TextBuffer);
  932.  
  933.  
  934.                                 /* Now, compute X-offset for printout. Take "Printer-Prefs" left margin - not
  935.                                    "PrinterGfx-Prefs" settings!
  936.                                 */
  937.                                 i = PD->pd_Preferences.PrintXOffset;        /* Remember to restore later */
  938.  
  939.                                 l = PD->pd_Preferences.PrintSpacing >> 10;    /* Get used printer's font */
  940.                                 if (l == 0)
  941.                                     l = 10;    /* Pica 10 cpi */
  942.                                 if (l == 1)
  943.                                     l = 12;    /* Elite 12 cpi */
  944.                                 if (l == 2)
  945.                                     l = 17;    /* Fine 15/17 cpi */
  946.  
  947.                                 /* E. g.: 30 (left margin) * 10 / 10 (Pica = 10 cpi) = 30(/10ths inch) */
  948.                                 PD->pd_Preferences.PrintXOffset = PD->pd_Preferences.PrintLeftMargin * 10 / l;
  949.  
  950.                                 /* Print out graphic */
  951.                                 DoTheDump( p);
  952.  
  953.                                 PD->pd_Preferences.PrintXOffset = i;
  954.                             }
  955.                         }
  956.                     }
  957.                     else
  958.                         PsMsg->pm_Tell( GStr( "\000\x1C Invalid screen-mode-ID") );
  959.  
  960.                     CloseDevice( (struct IORequest *) PIO);
  961.                 }
  962.                 else
  963.                     PsMsg->pm_Tell( GStr( "\000\x1D Cannot open the \"printer device\"") );
  964.  
  965.                 DeleteExtIO( (struct IORequest *) PIO);
  966.  
  967.             }
  968.             else
  969.                 PsMsg->pm_Tell( GStr( "\000\x1E Cannot create required I/O-request") );
  970.  
  971.             DeleteMsgPort( PrinterPort);
  972.  
  973.         }
  974.         else
  975.             PsMsg->pm_Tell( GStr( "\000\x1F Cannot create a message port") );
  976.  
  977.     }
  978.  
  979.     if (FakeBM)
  980.         FreeMem( FakeBM, sizeof( struct BitMap));
  981.     if (FakeRP)
  982.         FreeMem( FakeRP, sizeof( struct RastPort));
  983.     if (TextBuffer)
  984.         FreeMem( TextBuffer, TEXTBUFFERSIZE);
  985.  
  986.     CloseTheCatalog();
  987.  
  988.     return 0;
  989. }
  990.  
  991. /*
  992.     This is the end of DAC-Dump - if you can do better than me - feel free to modify.
  993. */